package com.pro01.backend.service;

import com.pro01.backend.dto.ActiveTorrentDTO;
import com.pro01.backend.dto.TorrentWithConnectionDTO;
import com.pro01.backend.dto.UserRatioDTO;
import com.pro01.backend.exception.DownloadLimitExceededException;
import com.pro01.backend.exception.LowShareRatioException;
import com.pro01.backend.exception.UserWarnedException;
import com.pro01.backend.mapper.*;
import com.pro01.backend.pojo.*;
import com.pro01.backend.tracker.TrackerManager;
import com.pro01.backend.utils.TorrentModifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.turn.ttorrent.common.Torrent;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
public class TorrentService {

    @Autowired
    private TorrentMapper torrentMapper;

    @Autowired
    private TrackerManager trackerManager;

    @Autowired
    private TorrentDownloadMapper torrentDownloadMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PromotionMapper promotionMapper;

    @Autowired
    private UserPromotionMapper userPromotionMapper;

    @Autowired
    private PointService pointService;

    @Autowired
    private UserPromotion2Mapper userPromotion2Mapper;

    @Autowired
    private Promotion2Mapper promotion2Mapper;

    @Autowired
    private RatioService ratioService;


    // 自动获取项目根路径下的 upload 目录
    private final String UPLOAD_DIR = System.getProperty("user.dir") + "/uploads/torrents/";

    public boolean uploadTorrent(Long userId, String name, String category, MultipartFile file) {
        if (file.isEmpty()) {
            throw new RuntimeException("上传的种子文件不能为空");
        }

        try {
            // 生成唯一文件名
            String originalFilename = file.getOriginalFilename();
//            String newFileName = UUID.randomUUID() + "_" + originalFilename;
//
//            // 保存文件
//            File dest = new File(UPLOAD_DIR + newFileName);
//            file.transferTo(dest);

            File dest = new File(UPLOAD_DIR + originalFilename);
            file.transferTo(dest);


            // 初始化 info_hash
            String infoHash = null;

            long totalSize = 0;
            // 如果是 .torrent 文件，注册 tracker 并提取 info_hash
            if (originalFilename != null && originalFilename.endsWith(".torrent")) {
                trackerManager.registerTorrent(dest);

                // 解析 .torrent 文件
                Torrent parsedTorrent = Torrent.load(dest);
                infoHash = parsedTorrent.getHexInfoHash();
                totalSize = parsedTorrent.getSize();  // 新增：获取种子里描述的原始数据大小
            }

            // 创建种子对象5
            TorrentClass torrent = new TorrentClass();
            torrent.setUserId(userId);
            torrent.setName(name);
            torrent.setCategory(category);
            torrent.setFilePath(UPLOAD_DIR + originalFilename);
            //torrent.setSize(file.getSize());
            torrent.setSize(totalSize);
            torrent.setInfoHash(infoHash); // 设置 info_hash

            // 1. 先插入种子
            int inserted = torrentMapper.insertTorrent(torrent);

            // 2. 判断成功后刷新
            if (inserted > 0) {
                userService.refreshCreditAndLevel(userId);

                // 发帖加积分
                pointService.addUploadReward(userId);
                return true;
            } else {
                return false;
            }

        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("种子上传失败");
        }
    }



//    public List<TorrentClass> getAllTorrents() {
//        return torrentMapper.getAllTorrents();
//    }

    //分页显示所有种子
    public PageResult<TorrentClass> getAllTorrentsPaged(int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<TorrentClass> torrents = torrentMapper.getAllTorrentsPaged(offset, pageSize);
        int total = torrentMapper.countAllTorrents();

        PageResult<TorrentClass> pageResult = new PageResult<>();
        pageResult.setRecords(torrents);
        pageResult.setTotal(total);
        return pageResult;
    }


//    public List<TorrentClass> getTorrentsByCategory(String category) {
//        return torrentMapper.getTorrentsByCategory(category);
//    }
    //根据类别查询种子
    public PageResult<TorrentClass> getTorrentsByCategoryPaged(String category, int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<TorrentClass> torrents = torrentMapper.getTorrentsByCategoryPaged(category, offset, pageSize);
        int total = torrentMapper.countTorrentsByCategory(category);

        PageResult<TorrentClass> pageResult = new PageResult<>();
        pageResult.setRecords(torrents);
        pageResult.setTotal(total);
        return pageResult;
    }

    // 🔍 搜索种子 + 返回分页结果
    public PageResult<TorrentClass> searchTorrentsByKeyword(String keyword, int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<TorrentClass> torrents = torrentMapper.searchTorrentsByKeyword(keyword, offset, pageSize);
        int total = torrentMapper.countTorrentsByKeyword(keyword);

        PageResult<TorrentClass> pageResult = new PageResult<>();
        pageResult.setRecords(torrents);
        pageResult.setTotal(total);

        return pageResult;
    }

    // 🔥 用户查看自己上传的种子（分页）
    public PageResult<TorrentClass> getUserUploadedTorrents(Long userId, int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<TorrentClass> torrents = torrentMapper.getUserUploadedTorrents(userId, offset, pageSize);
        int total = torrentMapper.countUserUploadedTorrents(userId);

        PageResult<TorrentClass> pageResult = new PageResult<>();
        pageResult.setRecords(torrents);
        pageResult.setTotal(total);

        return pageResult;
    }

    /**
     * 用户分页查看自己的下载记录
     */
//    public PageResult<Map<String, Object>> getUserDownloadRecords(Long userId, int pageNum, int pageSize) {
//        int offset = (pageNum - 1) * pageSize;
//        List<Map<String, Object>> records = torrentDownloadMapper.getUserDownloadedTorrents(userId, offset, pageSize);
//        int total = torrentDownloadMapper.countUserDownloadedTorrents(userId);
//
//        PageResult<Map<String, Object>> result = new PageResult<>();
//        result.setRecords(records);
//        result.setTotal(total);
//        return result;
//    }
    public PageResult<TorrentDownload> getUserDownloadRecords(Long userId, int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<TorrentDownload> records = torrentDownloadMapper.getUserDownloadedTorrents(userId, offset, pageSize);
        int total = torrentDownloadMapper.countUserDownloadedTorrents(userId);
        return new PageResult<>(total, records);
    }


    public TorrentClass getTorrentById(Long id) {
        return torrentMapper.getTorrentById(id);
    }

    public boolean deleteTorrent(Long id) {
        return torrentMapper.deleteTorrent(id) > 0;
    }


    // 下载种子文件，并记录下载行为
    @Transactional
    public File downloadTorrent(Long userId, Long torrentId) {
        User user = userMapper.getUserById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        // 1. 先校验用户能否下载
        checkUserDownloadPermission(user);

        TorrentClass torrent = torrentMapper.getTorrentById(torrentId);
        if (torrent == null) {
            throw new RuntimeException("种子不存在");
        }

        // 生成 peer_id
        String peerId = generatePeerId();

        // 记录下载行为
        TorrentDownload record = new TorrentDownload();
        record.setUserId(userId);
        record.setTorrentId(torrentId);
        record.setPeerId(peerId);
        torrentDownloadMapper.insertDownload(record);

        // ✅ 下载行为插入成功后，刷新用户贡献度、等级
        userService.refreshCreditAndLevel(userId);

        // ======= 下载完成后，处理促销奖励 =======
        Promotion promo = promotionMapper.getActivePromotionByTorrentId(torrentId);
        if (promo != null) {
            // 检查是否已经领取过
            boolean alreadyClaimed = userPromotionMapper.existsByUserAndTorrent(userId, torrentId);
            if (!alreadyClaimed) {
                int bonusCredit = 0;
                int bonusUpload = 0;
                int bonusDownload = 0;

                switch (promo.getPromotionType()) {
                    case "FREE" -> bonusDownload = 1;
                    case "DOUBLE_UPLOAD" -> {
                        bonusUpload = 1;
                        bonusCredit = 20;
                    }
                    case "SEED_BONUS" -> bonusCredit = 10;
                }

                // 插入用户促销记录
                UserPromotion up = new UserPromotion();
                up.setUserId(userId);
                up.setTorrentId(torrentId);
                up.setPromotionType(promo.getPromotionType());
                up.setBonusCredit((long) bonusCredit);
                up.setBonusUpload(bonusUpload);
                up.setBonusDownload(bonusDownload);
                userPromotionMapper.insertUserPromotion(up);

                // 更新用户 bonus 字段
                userMapper.updateBonusValues(userId, bonusCredit, bonusUpload, bonusDownload);
            }
        }


        // 修改 .torrent 文件注入 peer_id
        File originalFile = new File(torrent.getFilePath());
        try {
            return TorrentModifier.injectPeerIdIntoAnnounce(originalFile, peerId);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("注入 peer_id 失败");
        }
    }

    @Transactional
    public File downloadTorrentWithPasskey(Long userId, Long torrentId) {
        User user = userMapper.getUserById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        checkUserDownloadPermission(user);

        TorrentClass torrent = torrentMapper.getTorrentById(torrentId);
        if (torrent == null) {
            throw new RuntimeException("种子不存在");
        }

        String passkey = user.getPasskey();
        if (passkey == null || passkey.isEmpty()) {
            throw new RuntimeException("用户尚未分配 passkey");
        }

        // 记录下载行为（仍用 peer_id 字段占位）
        TorrentDownload record = new TorrentDownload();
        record.setUserId(userId);
        record.setTorrentId(torrentId);
        record.setPeerId("passkey_" + passkey); // 可自定义格式
        torrentDownloadMapper.insertDownload(record);

        userService.refreshCreditAndLevel(userId);

        // ======= 下载完成后，处理促销奖励 =======
        Promotion promo = promotionMapper.getActivePromotionByTorrentId(torrentId);
        if (promo != null) {
            // 检查是否已经领取过
            boolean alreadyClaimed = userPromotionMapper.existsByUserAndTorrent(userId, torrentId);
            if (!alreadyClaimed) {
                int bonusCredit = 0;
                int bonusUpload = 0;
                int bonusDownload = 0;

                switch (promo.getPromotionType()) {
                    case "FREE" -> bonusDownload = 1;
                    case "DOUBLE_UPLOAD" -> {
                        bonusUpload = 1;
                        bonusCredit = 20;
                    }
                    case "SEED_BONUS" -> bonusCredit = 10;
                }

                // 插入用户促销记录
                UserPromotion up = new UserPromotion();
                up.setUserId(userId);
                up.setTorrentId(torrentId);
                up.setPromotionType(promo.getPromotionType());
                up.setBonusCredit((long) bonusCredit);
                up.setBonusUpload(bonusUpload);
                up.setBonusDownload(bonusDownload);
                userPromotionMapper.insertUserPromotion(up);

                // 更新用户 bonus 字段
                userMapper.updateBonusValues(userId, bonusCredit, bonusUpload, bonusDownload);
            }
        }

        // ======= 下载完成后，处理促销奖励（流量版） =======
        Promotion2 promo2 = promotion2Mapper.getActivePromotionByTorrentId(torrentId);
        if (promo2 != null && promo2.getPromotionType() != null) {
            Timestamp now = new Timestamp(System.currentTimeMillis());

            // FREE: 下载者获得 reward_downloaded
            if ("FREE".equals(promo2.getPromotionType())) {
                boolean claimed = userPromotion2Mapper.hasReceived(userId, torrentId, "FREE");
                if (!claimed) {
                    UserPromotion2 rewardRecord = new UserPromotion2();
                    rewardRecord.setUserId(userId);
                    rewardRecord.setTorrentId(torrentId);
                    rewardRecord.setPromotionType("FREE");
                    rewardRecord.setRewardDownloaded(torrent.getSize());
                    rewardRecord.setRewardUploaded(0L);
                    rewardRecord.setRewardCredit(0L);
                    rewardRecord.setCreatedAt(now);
                    userPromotion2Mapper.insertReward(rewardRecord);
                }
            }

            // DOUBLE_UPLOAD: 上传者获得 reward_uploaded
            if ("DOUBLE_UPLOAD".equals(promo2.getPromotionType())) {
                Long uploaderId = torrent.getUserId();
                if (uploaderId != null && !uploaderId.equals(userId)) {
                    boolean uploaderClaimed = userPromotion2Mapper.hasReceived(uploaderId, torrentId, "DOUBLE_UPLOAD");
                    if (!uploaderClaimed) {
                        UserPromotion2 uploadRecord = new UserPromotion2();
                        uploadRecord.setUserId(uploaderId);
                        uploadRecord.setTorrentId(torrentId);
                        uploadRecord.setPromotionType("DOUBLE_UPLOAD");
                        uploadRecord.setRewardUploaded(torrent.getSize());
                        uploadRecord.setRewardDownloaded(0L);
                        uploadRecord.setRewardCredit(0L);
                        uploadRecord.setCreatedAt(now);
                        userPromotion2Mapper.insertReward(uploadRecord);
                    }
                }
            }

            // SEED_BONUS 做种奖励将在定时任务中处理
        }

        // 注入 passkey 到 announce 字段
        File originalFile = new File(torrent.getFilePath());
        try {
            return TorrentModifier.injectPasskeyIntoAnnounce(originalFile, passkey);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("注入 passkey 失败");
        }
    }


    private void checkUserDownloadPermission(User user) {
        // 1. 警告状态禁止下载
        if ("WARNED".equals(user.getStatus())) {
//            throw new RuntimeException("你已被警告，无法下载种子！");
            throw new UserWarnedException("你已被警告，无法下载种子！");
        }

        // 2. 准分享率过低禁止下载
//        if (user.getVirtualRatio() != null && user.getVirtualRatio() < 0.3f) {
//            throw new RuntimeException("你的准分享率过低（小于 0.3），无法下载种子！");
//        }

        UserRatioDTO ratio = ratioService.getUserRewardedRatio(user.getId());
        if (ratio.getShareRatio() < 0.3f) {
//            throw new RuntimeException("你的准分享率过低（小于 0.3），无法下载种子！");
            throw new LowShareRatioException("你的分享率过低（小于 0.3），无法下载种子！");
        }
        // 3. 每日下载次数限制
        int todayDownloadCount = torrentDownloadMapper.countTodayDownloadsByUserId(user.getId());
        int dailyLimit = getDailyDownloadLimit(user.getLevel());

        if (dailyLimit > 0 && todayDownloadCount >= dailyLimit) {
//            throw new RuntimeException("今日下载次数已达上限，无法继续下载！");
            throw new DownloadLimitExceededException("今日下载次数已达上限，无法继续下载！");
        }
    }

    private int getDailyDownloadLimit(String level) {
        if (level == null) return 3; // 没等级就按新手算

        switch (level) {
            case "新手":
                return 3;
            case "普通用户":
                return 10;
            case "进阶用户":
                return 30;
            case "高级用户":
                return 0; // 0 表示无限制
            default:
                return 3; // 默认也按新手处理
        }
    }


    //生成peer_id
    private String generatePeerId() {
        String prefix = "-PTDAVID-";
        String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 12);
        return prefix + uuid;
    }

    /**
     * 以下是管理员的接口
     */

    // 查询所有种子
    public PageResult<TorrentClass> getAllTorrentsForAdmin(int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<TorrentClass> torrents = torrentMapper.getAllTorrentsForAdmin(offset, pageSize);
        int total = torrentMapper.countAllTorrentsForAdmin();
        return new PageResult<>(total, torrents);
    }

    // 管理员逻辑删除种子
    public boolean adminDeleteTorrent(Long torrentId) {
        return torrentMapper.deleteTorrent(torrentId) > 0;
    }

    // 管理员根据文件名模糊查询种子
    public PageResult<Map<String, Object>> searchTorrentsWithUploader(String keyword, int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<Map<String, Object>> torrents = torrentMapper.searchTorrentsWithUploader(keyword, offset, pageSize);
        int total = torrentMapper.countTorrentsByName(keyword);

        PageResult<Map<String, Object>> pageResult = new PageResult<>();
        pageResult.setRecords(torrents);
        pageResult.setTotal(total);
        return pageResult;
    }

    // 管理员根据用户名模糊查询文件
    public PageResult<Map<String, Object>> searchTorrentsByUploader(String uploaderName, int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<Map<String, Object>> torrents = torrentMapper.searchTorrentsByUploader(uploaderName, offset, pageSize);
        int total = torrentMapper.countTorrentsByUploader(uploaderName);

        PageResult<Map<String, Object>> pageResult = new PageResult<>();
        pageResult.setRecords(torrents);
        pageResult.setTotal(total);
        return pageResult;
    }

    // 管理员根据状态模糊查询文件
    public PageResult<Map<String, Object>> searchTorrentsByStatus(String status, int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<Map<String, Object>> torrents = torrentMapper.searchTorrentsByStatus(status, offset, pageSize);
        int total = torrentMapper.countTorrentsByStatus(status);

        PageResult<Map<String, Object>> pageResult = new PageResult<>();
        pageResult.setRecords(torrents);
        pageResult.setTotal(total);
        return pageResult;
    }

    /**
     * 接下来是种子促销逻辑
     */
    // 设置促销(仅限管理员)
    @Transactional
    public boolean promoteTorrent(Long torrentId, String type, int hours) {
        // 1. 计算促销结束时间
        Timestamp endTime = Timestamp.from(Instant.now().plus(hours, ChronoUnit.HOURS));

        // 2. 更新 torrents 表
        int updateRows = torrentMapper.updatePromotionStatus(torrentId, type, endTime);
        if (updateRows <= 0) {
            throw new RuntimeException("种子促销失败，找不到该种子或更新失败！");
        }

        // 3. 新增一条记录到 promotions 表
        Promotion promotion = new Promotion();
        promotion.setTorrentId(torrentId);
        promotion.setPromotionType(type);
        promotion.setStartTime(Timestamp.from(Instant.now()));
        promotion.setEndTime(endTime);
        promotion.setCreatedAt(Timestamp.from(Instant.now()));

        int insertRows = promotionMapper.insertPromotion(promotion);
        if (insertRows <= 0) {
            throw new RuntimeException("促销记录插入失败！");
        }

        return true;
    }

    // 取消促销(仅限管理员)
    @Transactional
    public boolean cancelPromotion(Long torrentId) {
        // 1. 更新 torrents 表，将促销状态清空
        int updateRows = torrentMapper.updatePromotionStatus(torrentId, "NONE", null);
        if (updateRows <= 0) {
            throw new RuntimeException("取消促销失败，找不到该种子或更新失败！");
        }

        // 2. 插入一条 promotions 表记录（可选）
        Promotion cancelRecord = new Promotion();
        cancelRecord.setTorrentId(torrentId);
        cancelRecord.setPromotionType("CANCEL"); // 特殊标记一下
        cancelRecord.setStartTime(Timestamp.from(Instant.now())); // 取消时间
        cancelRecord.setEndTime(null); // 取消促销没有结束时间
        cancelRecord.setCreatedAt(Timestamp.from(Instant.now()));

        promotionMapper.insertPromotion(cancelRecord);

        return true;
    }

    // 查询当前有效促销种子
    public PageResult<Map<String, Object>> getActivePromotions(int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<Map<String, Object>> records = torrentMapper.getActivePromotions(offset, pageSize);
        int total = torrentMapper.countActivePromotions();

        return new PageResult<>(total, records);
    }

    // 连接性检测
    public PageResult<ActiveTorrentDTO> getActiveTorrents(int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<ActiveTorrentDTO> list = torrentMapper.getActiveTorrentsPaged(offset, pageSize);
        int total = torrentMapper.countActiveTorrents();
        return new PageResult<>(total, list);
    }

    // 种子连接性检测
    public PageResult<TorrentWithConnectionDTO> getAllTorrentsWithConnection(int pageNum, int pageSize) {
        int offset = (pageNum - 1) * pageSize;
        List<TorrentWithConnectionDTO> list = torrentMapper.getTorrentsWithConnection(offset, pageSize);
        int total = torrentMapper.countAllTorrents();
        return new PageResult<>(total, list);
    }

}
